import java.lang.Class;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ClassTest {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        /** 获取Class实列 */
        // 通过Class获取
        Class cls1 = StudentTest.class;

        // 通过实列获取
        StudentTest studentTest = new StudentTest("A", 1);
        Class cls2 = studentTest.getClass();
        Field f = cls2.getDeclaredField("name");
        f.setAccessible(true);  // 设置下 get方法才可以获取私有变量 否则会报错
        f.set(studentTest, "B");
        Object value = f.get(studentTest);  // 获取值
        System.out.println(value);  // A

        // 构造方法
        Constructor cons1 = StudentTest.class.getConstructor(String.class, int.class);  // 获取参数是String和int的构造函数
        StudentTest studentTest2 = (StudentTest) cons1.newInstance("C", 1);
        System.out.println(studentTest2.getName());  // C

        /** 注解 */
        Method m1 = cls2.getMethod("getName");
        System.out.println(m1.invoke(studentTest));
        System.out.println(m1.isAnnotationPresent(Report.class));  // 判断注解是否存在
        Report report = m1.getAnnotation(Report.class);  // 获取注解 如果Annotation不存在，将返回null：
        int type = report.type();
        String level = report.level();
        System.out.println(type);
        System.out.println(level);
    }

}

/**
 * 定义一个注解
 */
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Report {
    int type() default 0;

    String level() default "info";

    String value() default "";
}


class StudentTest {
    protected String name;
    protected int score;

    public StudentTest(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Report(type=1)
    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }
}